package com.example.project.projectspringcloud.controller.front;

import cn.hutool.core.util.RandomUtil;
import com.example.project.projectspringcloud.common.Constants;
import com.example.project.projectspringcloud.common.OperationException;
import com.example.project.projectspringcloud.controller.BaseController;
import com.example.project.projectspringcloud.entity.Page;
import com.example.project.projectspringcloud.entity.RespBody;
import com.example.project.projectspringcloud.entity.sys.SysConfig;
import com.example.project.projectspringcloud.entity.user.Collect;
import com.example.project.projectspringcloud.entity.user.User;
import com.example.project.projectspringcloud.entity.user.UserProfile;
import com.example.project.projectspringcloud.entity.user.pojo.UserPojo;
import com.example.project.projectspringcloud.entity.video.Video;
import com.example.project.projectspringcloud.service.sys.SysConfigService;
import com.example.project.projectspringcloud.service.user.UserCollectService;
import com.example.project.projectspringcloud.service.user.UserProfileService;
import com.example.project.projectspringcloud.service.user.UserService;
import com.example.project.projectspringcloud.service.video.VideoService;
import com.example.project.projectspringcloud.utils.AliSmsUtil;
import com.example.project.projectspringcloud.utils.PatterUtil;
import com.example.project.projectspringcloud.utils.RedisUtil;
import com.qq.connect.oauth.Oauth;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Random;

@Api(tags = "首页控制器")
@Controller
@RequestMapping(value = "/")
public class IndexController extends BaseController {

    private static Logger logger = LoggerFactory.getLogger(IndexController.class);

    @Autowired
    private VideoService videoService;

    @Autowired
    private UserService userService;

    @Autowired
    private SysConfigService sysConfigService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserProfileService userProfileService;

    @Autowired
    private UserCollectService userCollectService;

    @ApiOperation(value = "首页", notes = "展示精选短视频和用户")
    @GetMapping(value = {"", "/index"})
    public String index(Model model, HttpServletRequest request) throws Exception {
        // 获取后台配置开启首页显示的视频
        Video video = new Video();
        video.setCollectUser(super.getCurrentUserId());
        video.setFiltrates(new Integer[]{1});
        video.setOrderStr("video.order DESC");
        List<Video> videos = videoService.list(isMobile() ? new Page(0, 6) : new Page(0, 10), video);

        // 获取后台配置开启首页显示的摄影师/编剧
        User user = new User();
        user.setCollectUser(super.getCurrentUserId());
        user.setFiltrates(new Integer[]{1});
        user.setOrderStr("`order` DESC");
        List<User> users = userService.list(isMobile() ? new Page(0, 6) : new Page(0, 8), user);

        if (getCurrentUser() != null) {
            // 获取收藏的摄影师/编剧列表
            List<Collect> collects = userCollectService.list(null, new Collect(getCurrentUser().getId(), 1));
            model.addAttribute("collects", collects);
        }

        model.addAttribute("videoPage", new Page<Video>(videos));
        model.addAttribute("userPage", new Page<User>(users));

        return isMobile() ? "m/index" : "index";
    }

    /**
     * 跳转登录页面
     *
     * @return
     */
    @GetMapping(value = "/login")
    public String login() {
        return isMobile() ? "m/login" : "login";
    }

    @GetMapping(value = "/login-sms")
    public String smsLogin() {
        return "m/login-phone";
    }

    /**
     * 跳转注册页面
     *
     * @return
     */
    @GetMapping(value = "/register")
    public String register() {
        return isMobile() ? "m/register" : "register";
    }

    /**
     * 找回密码
     *
     * @return
     */
    @GetMapping(value = "/retrieve")
    public String retrieve(Model model) {
        model.addAttribute("currentUser", super.getCurrentUser());
        return isMobile() ? "m/content/personal/retrieve-password" : "retrieve";
    }

    @ApiOperation(value = "表单注册", notes = "注册成功直接登录")
    @PostMapping(value = "/regist/{step}")
    public String regist(@PathVariable("step") String step,
                         @Valid UserPojo user, BindingResult bindingResult, Model model, HttpServletRequest request) {

        if ("one".equals(step)) {
            // validate account, mobile, password, nickname
            if (bindingResult.getErrorCount() > 0) {
                model.addAttribute("error", super.translateI18N(bindingResult));
                return "m/register";
            }

            User entity = new User();
            entity.setMobile(user.getMobile());
            entity = userService.get(entity);
            // 手机号已经注册
            if (entity != null) {
                model.addAttribute("error", super.translateI18N(Constants.Tip.ACCOUNT_MOBILE_EXIST));
                return "m/register";
            }

            if (!redisUtil.hasKey(Constants.SMS_VALIDATE_CODE_OF + user.getMobile())
                    || !user.getValidate().equals(redisUtil.get(Constants.SMS_VALIDATE_CODE_OF + user.getMobile()))) {
                model.addAttribute("error", super.translateI18N(Constants.Tip.SMS_VALIDATE_CODE_DIFFERENT));
                return "m/register";
            }

            redisUtil.del(Constants.SMS_VALIDATE_CODE_OF + user.getMobile());

            request.getSession().setAttribute("regist-step-one-mobile", user.getMobile());
            request.getSession().setAttribute("regist-step-one-pwd", user.getPassword());
            return "m/register-set";
        }

        String mobile = (String) request.getSession().getAttribute("regist-step-one-mobile");
        String password = (String) request.getSession().getAttribute("regist-step-one-pwd");
        user.setMobile(mobile);
        user.setPassword(password);

        // 再次密码不一致
        /*if (!user.getPassword().equals(user.getPasswords())) {
            model.addAttribute("error", super.translateI18N(Constants.Tip.THE_TWO_PASSWORD_ARE_DIFFERENT));
            return isMobile() ? "m/register" : "content/register";
        }*/

        if (StringUtils.isBlank(user.getWechat())) {
            model.addAttribute("error", super.translateI18N(Constants.Tip.WECHAT_CNA_NOT_BE_NULL));
            return "m/register-set";
        }

        try {
            userService.register(user);
        } catch (OperationException e) {
            logger.error("IndexController.regist", e);
            model.addAttribute("error", super.translateI18N(e.getMessage()));
            return isMobile() ? "m/register" : "content/register";
        }
        return "redirect:/login";
    }

    /**
     * 普通用户注册
     *
     * @return
     */
    @ApiOperation(value = "API注册", notes = "普通用户/第三方账号注册")
    @PostMapping(value = "/api/regist")
    @ResponseBody
    public RespBody regist(@Valid UserPojo user, BindingResult bindingResult) {
        // validate account, mobile, password, nickname
        if (bindingResult.getErrorCount() > 0) {
            return RespBody.error(RespBody.ERROR_VALIDATE_CODE, super.translateI18N(bindingResult));
        }
        // 再次密码不一致
        if (!user.getPassword().equals(user.getPasswords())) {
            return RespBody.error(RespBody.ERROR_VALIDATE_CODE, super.translateI18N(Constants.Tip.THE_TWO_PASSWORD_ARE_DIFFERENT));
        }

        if (!redisUtil.hasKey(Constants.SMS_VALIDATE_CODE_OF + user.getMobile())
                || !user.getValidate().equals(redisUtil.get(Constants.SMS_VALIDATE_CODE_OF + user.getMobile()))) {
            return RespBody.error(super.translateI18N(Constants.Tip.SMS_VALIDATE_CODE_DIFFERENT));
        }

        try {
            userService.register(user);
        } catch (OperationException e) {
            logger.error("IndexController.regist", e);
            return RespBody.error(RespBody.ERROR_VALIDATE_CODE, super.translateI18N(e.getMessage()));
        }
        return RespBody.ok(true);
    }

    @ApiOperation(value = "按步修改密码", notes = "按步修改密码")
    @PostMapping(value = "/retrieve/{step}")
    public String modifyPassword(@ApiParam(value = "密码修改操作步骤") @PathVariable("step") Integer step,
                                 @RequestParam(value = "mobile", required = false) String mobile,
                                 @RequestParam(value = "smsCode", required = false) String smsCode,
                                 @RequestParam(value = "password", required = false) String password,
                                 @RequestParam(value = "passwords", required = false) String passwords,
                                 Model model, HttpServletRequest request) throws OperationException {
        switch (step) {
            case 1:
                // 校验短信验证码
                if (!redisUtil.hasKey(Constants.SMS_VALIDATE_CODE_OF + mobile)
                        || !smsCode.equals(redisUtil.get(Constants.SMS_VALIDATE_CODE_OF + mobile))) {
                    model.addAttribute("error", super.translateI18N(Constants.Tip.SMS_VALIDATE_CODE_DIFFERENT));
                    return "m/content/personal/retrieve-password";
                }
                redisUtil.del(Constants.SMS_VALIDATE_CODE_OF + mobile);
                request.getSession().setAttribute("step", 2);
                request.getSession().setAttribute("mobile", mobile);
                return "m/content/personal/retrieve-password-2";

            case 2:
                Integer temp = (Integer) request.getSession().getAttribute("step");
                mobile = (String) request.getSession().getAttribute("mobile");
                if (temp == null || temp != 2 || StringUtils.isBlank(mobile)) {
                    throw new OperationException();
                }

                try {
                    User user = new User();
                    user.setMobile(mobile);
                    userService.changePassword(userService.get(user), password, passwords);
                    return "m/content/personal/retrieve-password-3";
                } catch (OperationException e) {
                    model.addAttribute("error", super.translateI18N(e.getLocalizedMessage()));
                    return "m/content/personal/retrieve-password-2";
                }
            default:
                return "redirect:/404";
        }
    }

    @ApiOperation(value = "API找回密码", notes = "普通用户找回密码")
    @PostMapping(value = "/api/retrieve")
    @ResponseBody
    public RespBody retrieve(@Valid UserPojo user, BindingResult bindingResult) {
        // validate account, mobile, password, nickname
        if (bindingResult.getErrorCount() > 0) {
            return RespBody.error(RespBody.ERROR_VALIDATE_CODE, super.translateI18N(bindingResult));
        }
        // 再次密码不一致
        if (!user.getPassword().equals(user.getPasswords())) {
            return RespBody.error(RespBody.ERROR_VALIDATE_CODE, super.translateI18N(Constants.Tip.THE_TWO_PASSWORD_ARE_DIFFERENT));
        }

        if (!redisUtil.hasKey(Constants.SMS_VALIDATE_CODE_OF + user.getMobile())
                || !user.getValidate().equals(redisUtil.get(Constants.SMS_VALIDATE_CODE_OF + user.getMobile()))) {
            return RespBody.error(super.translateI18N(Constants.Tip.SMS_VALIDATE_CODE_DIFFERENT));
        }
        redisUtil.del(Constants.SMS_VALIDATE_CODE_OF + user.getMobile());
        try {
            // 找回
            userService.retrieve(user);
        } catch (OperationException e) {
            logger.error("IndexController.retrieve", e);
            return RespBody.error(RespBody.ERROR_VALIDATE_CODE, super.translateI18N(e.getMessage()));
        }

        return RespBody.ok(true);
    }


    /**
     * 图片验证码
     *
     * @param request
     * @param response
     * @throws IOException
     */
    @ApiOperation(value = "获取图片验证码", tags = "返回随机图片验证码")
    @GetMapping(value = "/api/validate_code")
    public void genericRandomCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        byte width = 85;
        byte height = 28;

        response.setHeader("Cache-Control", "private,no-cache,no-store");
        response.setContentType("image/png");

        BufferedImage image = new BufferedImage(width, height, 2);
        Graphics2D g = image.createGraphics();
        g.setComposite(AlphaComposite.getInstance(3, 1.0F));
        g.setColor(new Color(231, 231, 231));
        g.fillRect(0, 0, width, height);
        g.setFont(new Font("Microsoft YaHei", 2, 24));
        String code = "";
        for (int responseOutputStream = 0; responseOutputStream < 4; ++responseOutputStream) {
            String rand = String.valueOf(new Random().nextInt(10));
            code += rand;
            g.setColor(new Color(121, 143, 96));
            g.drawString(rand, 13 * responseOutputStream + 16, 23);
        }
        g.dispose();

        request.getSession().setAttribute(Constants.VALIDATE_CODE, code);

        logger.info("Validate Code: " + code);

        drawLine(image, width, height);

        ServletOutputStream sos = response.getOutputStream();
        ImageIO.write(image, "png", sos);
        sos.close();
    }

    /**
     * 获取短信验证码
     *
     * @param mobile
     * @return
     * @throws Exception
     */
    @ApiOperation(value = "GET获取短信验证码", notes = "GET获取短信验证码")
    @GetMapping(value = "/api/sms_validate_code")
    @ResponseBody
    public RespBody mobileModify(@ApiParam(name = "mobile", value = "手机号码") String mobile) {
        if (!(StringUtils.isNotBlank(mobile) && PatterUtil.match(PatterUtil.Patterns.CHINA_MOBILE, mobile))) {
            return RespBody.error(translateI18N(Constants.Tip.MOBILE_FORMAL_ERROR));
        }
        if (redisUtil.hasKey(Constants.SMS_VALIDATE_CODE_TIME_OF + mobile)) {
            return RespBody.error(translateI18N(Constants.GET_SMS_FAILED_PLEASE_LATER));
        }
        try {
            String numbers = RandomUtil.randomNumbers(6);
            try {
                redisUtil.set(Constants.SMS_VALIDATE_CODE_OF + mobile, numbers, 300);
            } catch (Exception e) {
                e.printStackTrace();
            }
            boolean result = AliSmsUtil.sendSms(mobile, numbers);
            if (!result) {
                return RespBody.error(Constants.Message.GET_VALIDATE_CODE_ERROR);
            }
        } catch (OperationException e) {
            logger.error("UserController.mobileModify - GET:", e);
            return RespBody.error(super.translateI18N(Constants.SystemMessage.SYSTEM_ERROR));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return RespBody.ok(super.translateI18N(Constants.Message.OPERATION_SUCCESS));
    }

    @ApiOperation(value = "API获取短信验证码", notes = "根据当前用户手机号获取, 按不同类型返回")
    @GetMapping(value = "/api/sms_code")
    @ResponseBody
    public RespBody getSmsCode(@RequestParam("type") String type) throws Exception {
        String mobile = super.getCurrentUser().getMobile();
        if (StringUtils.isBlank(mobile)) {
            return RespBody.error("用户手机号不存在");
        }
        if (redisUtil.hasKey(Constants.SMS_VALIDATE_CODE_TIME_OF + mobile)) {
            return RespBody.error(translateI18N(Constants.GET_SMS_FAILED_PLEASE_LATER));
        }
        try {
            String numbers = RandomUtil.randomNumbers(6);
            redisUtil.set(Constants.SMS_VALIDATE_CODE_OF + mobile, numbers, 300);
            boolean result = AliSmsUtil.sendSms(mobile, numbers);
//            boolean result = sysConfigService.sms(mobile, Constants.SMS_VALIDATE_CODE_OF);
            if (!result) {
                return RespBody.error(Constants.Message.GET_VALIDATE_CODE_ERROR);
            }
        } catch (OperationException e) {
            logger.error("UserController.mobileModify - GET:", e);
            return RespBody.error(super.translateI18N(Constants.SystemMessage.SYSTEM_ERROR));
        }
        return RespBody.ok(super.translateI18N(Constants.Message.OPERATION_SUCCESS));
    }

    /**
     * 画干扰的线条
     *
     * @param image
     * @param width
     * @param height
     */
    private void drawLine(BufferedImage image, byte width, byte height) {
        Random random = new Random();
        // 干扰线数量
        int num = 3;
        Graphics2D g2 = (Graphics2D) image.getGraphics();
        for (int i = 0; i < num; i++) {
            int x1 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int x2 = random.nextInt(width);
            int y2 = random.nextInt(height);
            g2.setStroke(new BasicStroke(1.5F));
            g2.setColor(Color.BLUE);
            g2.drawLine(x1, y1, x2, y2);
        }
    }

    @ApiOperation(value = "转到QQ登录", notes = "重定向到QQ登录")
    @GetMapping(value = "/thirdpart/qq")
    public void qq(HttpServletRequest request, HttpServletResponse response) throws Exception {
        SysConfig sysConfig = sysConfigService.get(new SysConfig(Constants.SysConfigType.SYS_CONFIG_THIRD_PART_LOGIN_QQ_ON_OFF));
        if (Constants.SystemFlag.ON.toString().equals(sysConfig.getValue())) {
            response.sendRedirect(new Oauth().getAuthorizeURL(request));
        } else {
            response.sendRedirect("/index?message=QQ登录已关闭");
        }
    }

    @ApiOperation(value = "转到WeChat登录", notes = "重定向到WeChat登录")
    @GetMapping(value = "/thirdpart/wechat")
    public void wechat(HttpServletResponse response) throws Exception {
        SysConfig sysConfig = sysConfigService.get(new SysConfig(Constants.SysConfigType.SYS_CONFIG_THIRD_PART_LOGIN_WECHAT_ON_OFF));
        if (Constants.SystemFlag.ON.toString().equals(sysConfig.getValue())) {
            Map config = sysConfigService.configs(new SysConfig(Constants.SysConfigType.SYS_CONFIG_THIRD_PART_LOGIN_WECHAT));
            response.sendRedirect(
                    String.format("https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=%s&scope=%s&state=%s#wechat_redirect",
                            config.get("appid"),
                            config.get("redirect_uri") + (getCurrentUser() != null ? "?userId=" + getCurrentUser().getId() : ""),
                            config.get("response_type"),
                            config.get("scope"),
                            config.get("state")));
        } else {
            response.sendRedirect("/index?message=微信登录已关闭");
        }
    }

    @ApiOperation(value = "转到Sina Weibo登录", notes = "重定向到Sina Weibo登录")
    @GetMapping(value = "/thirdpart/sinaweibo")
    public void sinaweibo(HttpServletResponse response) throws Exception {
        SysConfig sysConfig = sysConfigService.get(new SysConfig(Constants.SysConfigType.SYS_CONFIG_THIRD_PART_LOGIN_SINAWEIBO_ON_OFF));
        if (Constants.SystemFlag.ON.toString().equals(sysConfig.getValue())) {
            weibo4j.Oauth oauth = new weibo4j.Oauth();
            response.sendRedirect(oauth.authorize("code", "916972202", "all"));
        } else {
            response.sendRedirect("/index?message=新浪微博登录已关闭");
        }
    }

    @ApiOperation(value = "解绑第三方账号", notes = "解绑第三方账号")
    @GetMapping(value = "/thirdpart/relieve/{type}")
    public String relieve(@PathVariable("type") String type) {
        UserProfile userProfile = new UserProfile();
        userProfile.setType(type);
        userProfile.setUserId(getCurrentUser().getId());
        userProfile = userProfileService.get(userProfile);
        userProfileService.delete(new Integer[]{userProfile.getId()});
        return "redirect:/personal/safe";
    }
}
